home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
Pakiet internetowy
/
Rozne
/
HTTrack 3.40-2
/
httrack-3.40-2.exe
/
{app}
/
src
/
mmsrip
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
2006-01-23
|
23KB
|
754 lines
/*
* $RCSfile: main.c,v $
* $Date: 2006/01/23 20:30:42 $ - $Revision: 1.32 $
*
* This file is distributed as a part of MMSRIP ( MMS Ripper ).
* Copyright (c) 2005-2006 Nicolas BENOIT
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "common.h"
#include "mms.h"
#include "error.h"
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
/*
* options
*/
#if defined(SOLARIS) || defined(sun)
static char * options = "ahvtqko:d:g:";
#else
static char * options = "-ahvtqko:d:g:";
#endif
#ifdef HAVE_GETOPT_LONG
static struct option long_options[] = {
{"about", 0, NULL, 'a'},
{"version", 0, NULL, 'v'},
{"help", 0, NULL, 'h'},
{"test", 0, NULL, 't'},
{"quiet", 0, NULL, 'q'},
{"trick", 0, NULL, 'k'},
{"output", 1, NULL, 'o'},
{"delay", 1, NULL, 'd'},
{"debug", 1, NULL, 'g'},
{NULL, 0, NULL, 0 }
};
#endif
/*
* usage
*/
void
usage ( void )
{
fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION );
fprintf ( stderr, "usage: %s <[-oFILE] stream url> ...\n\n", PROGRAM_SHORT_NAME );
#ifdef HAVE_GETOPT_LONG
fprintf ( stderr, "General Options:\n\t" \
"-a, --about\t\tshow information about %s\n\t" \
"-h, --help\t\tshow this help\n\t" \
"-v, --version\t\tshow version number\n\n" \
"Program Behaviour:\n\t" \
"-oFILE, --output=FILE\toutput to specified file (can be repeated)\n\t" \
"-gFILE, --debug=FILE\toutput debug info to specified file\n\t" \
"-q, --quiet\t\tquiet mode (can be repeated)\n\t" \
"-dDELAY, --delay=DELAY\tsave the stream during DELAY seconds and exit\n\t" \
"-k, --trick\t\tattempt to trick recalcitrant servers\n\t" \
"-t, --test\t\ttest mode (check stream availability)\n\n", PROGRAM_SHORT_NAME );
#else
fprintf ( stderr, "General Options:\n\t" \
"-a\tshow information about %s\n\t" \
"-h\tshow this help\n\t" \
"-v\tshow version number\n\n" \
"Program Behaviour:\n\t" \
"-oFILE\toutput to specified file (can be repeated)\n\t" \
"-gFILE\toutput debug info to specified file\n\t" \
"-q\tquiet mode (can be repeated)\n\t" \
"-dDELAY\tsave the stream during DELAY seconds and exit\n\t" \
"-k\tattempt to trick recalcitrant servers\n\t" \
"-t\ttest mode (check stream availability)\n\n", PROGRAM_SHORT_NAME );
#endif
return;
}
/*
* main
*/
int
main ( int argc,
char *argv[] )
{
MMS *mms;
FILE *f;
FILE *stddebug = NULL;
char *output_filename;
STREAM_LIST *stream_list;
STREAM_LIST *block;
char c;
int ret = MMS_RET_SUCCESS;
int quiet = 0;
int trick = MMS_TRICK_DISABLED;
int retry = 0;
int test = 0;
int delay = 0;
time_t end = 0;
float speed = 0.0f;
struct timeval speed_last_update;
struct timeval now;
float elapsed_time;
ssize_t len_written;
uint64_t total_len_written = 0;
uint64_t old_total_len_written = 0;
if ( ( stream_list = (STREAM_LIST *) malloc(sizeof(STREAM_LIST)) ) == NULL )
{
error ( "main", "early initialization failed" );
return 1;
}
stream_list->next = NULL;
stream_list->stream = NULL;
stream_list->output = NULL;
block = stream_list;
#ifdef HAVE_GETOPT_LONG
while ( ( c = getopt_long(argc, argv, options, long_options, NULL) ) != -1 )
#elif defined(SOLARIS) || defined(sun)
/* Implementation of getopt in Solaris is a bit strange, it returns -1 even if there are still args to parse... */
while ( optind < argc )
#else
while ( ( c = getopt(argc, argv, options) ) != -1 )
#endif
{
#if defined(SOLARIS) || defined(sun)
c = getopt ( argc, argv, options );
#endif
switch (c)
{
case 'h':
{
fprintf ( stderr, "\n" );
usage();
return 0;
}
case 'v':
{
fprintf ( stderr, "%s version %s\n", PROGRAM_SHORT_NAME, PROGRAM_VERSION);
return 0;
}
case 'a':
{
fprintf ( stderr, "\n" );
fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION);
fprintf ( stderr, "Written by %s.\n", PROGRAM_AUTHORS );
fprintf ( stderr, "With a lot of help from %s.\n\n", PROGRAM_HELPERS );
fprintf ( stderr, "This program is free software; you can redistribute it and/or\nmodify it under the terms " \
"of the GNU General Public License\nas published by the Free Software Foundation; either version 2" \
",\nor (at your option) any later version.\n\n" );
return 0;
}
case 't':
{
test = 1;
break;
}
case 'q':
{
quiet += 1;
break;
}
case 'k':
{
trick = MMS_TRICK_ENABLED;
break;
}
case 'o':
{
if ( optarg != NULL )
{
if ( block->stream != NULL )
{
if ( ( block->next = malloc ( sizeof(STREAM_LIST) ) ) == NULL )
{
error ( "main", "early initialization failed" );
ret = MMS_RET_ERROR;
goto clean;
}
block = block->next;
block->next = NULL;
block->stream = NULL;
}
if ( block->output != NULL )
free ( block->output );
block->output = (char *) strdup ( optarg );
}
break;
}
case 'g':
{
if ( optarg != NULL )
{
if ( stddebug != NULL )
fclose ( stddebug );
if ( ( stddebug = fopen ( optarg, "w" ) ) == NULL )
{
if ( quiet < 2 )
#ifdef HAVE_VSNPRINTF
warning ( NULL, "unable to write debug info in \'%s\'", optarg );
#else
warning ( NULL, "unable to write debug info in specified file" );
#endif
}
else
{
fprintf ( stddebug, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION);
fprintf ( stddebug, "--> debug log begins now\n" );
}
}
break;
}
case 'd':
{
if ( optarg != NULL )
{
delay = atoi( optarg );
if ( delay < 0 )
delay = 0;
}
break;
}
#if defined(SOLARIS) || defined(sun)
case -1:
{
if ( optind >= argc )
break;
#else
case 1:
{
if ( optarg != NULL )
{
#endif
if ( block->stream != NULL )
{
if ( ( block->next = malloc ( sizeof(STREAM_LIST) ) ) == NULL )
{
error ( "main", "early initialization failed" );
ret = MMS_RET_ERROR;
goto clean;
}
block = block->next;
block->next = NULL;
block->output = NULL;
}
#if defined(SOLARIS) || defined(sun)
/* optind is not incremented when meeting something else than an option, so we do that... */
block->stream = (char *) strdup ( argv[optind++] );
#else
block->stream = (char *) strdup ( optarg );
}
#endif
break;
}
}
}
if ( stream_list->stream == NULL )
{
usage ( );
ret = MMS_RET_ERROR;
goto clean;
}
if ( !quiet )
{
fprintf ( stderr, "\n" );
fprintf ( stderr, "%s (%s) version %s\n\n", PROGRAM_SHORT_NAME, PROGRAM_FULL_NAME, PROGRAM_VERSION );
}
for ( block=stream_list; block!=NULL; block=(STREAM_LIST*)block->next )
{
if ( block->stream == NULL )
{
if ( quiet < 2 )
{
if ( block->output == NULL )
#ifdef HAVE_VSNPRINTF
error ( "main", "invalid invocation of %s", PROGRAM_SHORT_NAME );
#else
error ( "main", "invalid invocation of mmsrip" );
#endif
else
#ifdef HAVE_VSNPRINTF
error ( "main", "output to \'%s\' is not attached to any stream", block->output );
#else
error ( "main", "one of the -o output is not attached to any stream" );
#endif
}
ret = MMS_RET_ERROR;
goto clean;
}
if ( block->output == NULL )
{
char *tmp = strchr ( block->stream, '/' );
char *interro_ptr = strchr ( block->stream, '?' );
if ( interro_ptr == NULL )
output_filename = strrchr ( block->stream, '/' );
else
{
do /* we look for the last '/' before the first '?' */
{
output_filename = tmp;
tmp = strchr ( tmp+1, '/' );
}
while ( ( tmp < interro_ptr ) && ( tmp != NULL ) );
}
if ( output_filename == NULL )
{
if ( quiet < 2 )
#ifdef HAVE_VSNPRINTF
error ( "main", "malformed url: \'%s\'", block->stream );
#else
error ( "main", "malformed url" );
#endif
ret = MMS_RET_ERROR;
continue;
}
++output_filename;
if ( strlen ( output_filename ) == 0 )
{
if ( quiet < 2 )
#ifdef HAVE_VSNPRINTF
error ( "main", "malformed url: \'%s\'", block->stream );
#else
error ( "main", "malformed url" );
#endif
ret = MMS_RET_ERROR;
continue;
}
block->output = (char *) strdup ( output_filename );
/* we clean filenames that look like 'stream.asf?digest=7Q2bjXo&provider=lala' */
if ( ( interro_ptr = strchr(block->output,'?') ) != NULL )
*interro_ptr = '\0';
}
}
if ( ret != MMS_RET_SUCCESS )
goto clean;
if ( delay != 0 )
end = time(NULL) + delay;
for ( block=stream_list; block!=NULL; block=(STREAM_LIST*)(retry?block:block->next) )
{
output_filename = block->output;
retry = 0;
if ( !test )
{
if ( ( f = fopen ( output_filename, "w" ) ) == NULL )
{
if ( quiet < 2 )
#ifdef HAVE_VSNPRINTF
error ( "main", "unable to write in \'%s\'", output_filename );
#else
error ( "main", "unable to write in output file" );
#endif
ret = MMS_RET_ERROR;
continue;
}
}
else
f = NULL;
if ( ( mms = mms_create ( block->stream, f, stddebug, trick, test?1:(quiet>>1) ) ) == NULL )
{
if ( quiet < 2 )
error ( "main", "unable to create mms struct" );
if ( !test )
{
fclose ( f );
remove ( output_filename );
}
ret = MMS_RET_ERROR;
continue;
}
if ( !quiet )
fprintf ( stderr, "Connecting ...\r" );
if ( mms_connect ( mms ) != MMS_RET_SUCCESS )
{
if ( quiet < 2 )
error ( "main", "unable to connect" );
mms_destroy ( mms );
if ( !test )
{
fclose ( f );
remove ( output_filename );
}
ret = MMS_RET_ERROR;
continue;
}
if ( !quiet )
fprintf ( stderr, "Handshaking ...\r" );
if ( mms_handshake ( mms ) != MMS_RET_SUCCESS )
{
if ( ( quiet < 2 ) && ( !test ) )
error ( "main", "unable to handshake" );
mms_disconnect ( mms );
mms_destroy ( mms );
if ( !test )
{
fclose ( f );
remove ( output_filename );
}
if ( !quiet )
{
if ( !test )
fprintf ( stderr, "Stream \'%s\' is not good.\n\n", block->stream );
else
fprintf ( stderr, "Stream \'%s\' is not good.\n", block->stream );
}
ret = MMS_RET_ERROR;
continue;
}
if ( test )
{
if ( !quiet )
fprintf ( stderr, "Stream \'%s\' is available.\n", block->stream );
mms_disconnect ( mms );
mms_destroy ( mms );
continue;
}
if ( !quiet )
fprintf ( stderr, "Getting header ...\r" );
if ( ( len_written = mms_write_stream_header ( mms ) ) == MMS_RET_ERROR )
{
if ( quiet < 2 )
error ( "main", "unable to write stream header" );
mms_disconnect ( mms );
mms_destroy ( mms );
fclose ( f );
remove ( output_filename );
ret = MMS_RET_ERROR;
continue;
}
total_len_written = len_written;
if ( !quiet )
fprintf ( stderr, "Rip is about to start ...\r" );
if ( mms_begin_rip ( mms ) != MMS_RET_SUCCESS )
{
if ( quiet < 2 )
error ( "main", "unable to begin the rip" );
mms_disconnect ( mms );
mms_destroy ( mms );
fclose ( f );
remove ( output_filename );
ret = -1;
continue;
}
if ( mms->is_live == MMS_LIVE )
{
if ( !quiet )
{
fprintf ( stderr, " \r" );
fprintf ( stderr, "%s: %d bytes written (--.- kbps)\r", output_filename, (ssize_t)total_len_written );
gettimeofday ( &speed_last_update, NULL );
}
while ( 1 )
{
len_written = mms_write_stream_data ( mms );
if ( len_written == 0 )
break;
else if ( len_written == MMS_RET_ERROR )
{
if ( quiet < 2 )
error ( "main", "unable to write stream data" );
ret = MMS_RET_ERROR;
break;
}
else if ( len_written == MMS_RET_NO_AUTH )
{
if ( trick == MMS_TRICK_DISABLED )
{
/* we retry with the trick enabled */
if ( quiet < 2 )
fprintf ( stderr, "\r*** retrying with the anti-recalcitrant servers trick enabled ***\n" );
trick = MMS_TRICK_ENABLED;
retry = 1;
}
else
{
/* it's definitely not working */
if ( quiet < 2 )
error ( "main", "unable to write stream data" );
ret = MMS_RET_NO_AUTH;
}
break;
}
total_len_written += len_written;
if ( !quiet )
{
gettimeofday ( &now, NULL );
if ( now.tv_sec > speed_last_update.tv_sec )
{
elapsed_time = (now.tv_sec - speed_last_update.tv_sec) + ((now.tv_usec - speed_last_update.tv_usec) / 1000000.0f);
if ( elapsed_time >= 1.0f )
{
speed = ( ( ((float) (total_len_written-old_total_len_written)) / elapsed_time) / 1024.0f );
old_total_len_written = total_len_written;
gettimeofday ( &speed_last_update, NULL );
}
}
if ( speed > 0.0f )
{
if ( (speed / 1024.0f) >= 1.0f )
fprintf ( stderr, "%s: %d bytes written (%.1f mbps) \r", output_filename, (ssize_t)total_len_written, speed/1024.0f );
else
fprintf ( stderr, "%s: %d bytes written (%.1f kbps) \r", output_filename, (ssize_t)total_len_written, speed );
}
else
fprintf ( stderr, "%s: %d bytes written (--.- kbps) \r", output_filename, (ssize_t)total_len_written );
}
fflush ( f );
if ( delay != 0 )
{
if ( end <= time(NULL) )
{
delay = -1;
break;
}
}
}
/* for a live, we should rewrite the header */
if ( ( ret == MMS_RET_SUCCESS ) && ( !quiet ) && ( !retry ) )
fprintf ( stderr, "%s: %d bytes written \r", output_filename, (ssize_t)total_len_written );
}
else
{
register const double coef = 100.0 / (double) mms->expected_file_size;
if ( !quiet )
{
fprintf ( stderr, " \r" );
fprintf ( stderr, "%s: %.2f%% (--.- kbps)\r", output_filename, (double) total_len_written * coef );
gettimeofday ( &speed_last_update, NULL );
}
while ( 1 )
{
len_written = mms_write_stream_data ( mms );
if ( len_written == 0 )
break;
else if ( len_written == MMS_RET_ERROR )
{
if ( quiet < 2 )
error ( "main", "unable to write stream data" );
ret = MMS_RET_ERROR;
break;
}
else if ( len_written == MMS_RET_NO_AUTH )
{
if ( trick == MMS_TRICK_DISABLED )
{
/* we retry with the trick enabled */
if ( quiet < 2 )
fprintf ( stderr, "\r*** retrying with the anti-recalcitrant servers trick enabled ***\n" );
trick = MMS_TRICK_ENABLED;
retry = 1;
}
else
{
/* it's definitely not working */
if ( quiet < 2 )
error ( "main", "unable to write stream data" );
ret = MMS_RET_NO_AUTH;
}
break;
}
total_len_written += len_written;
if ( !quiet )
{
gettimeofday ( &now, NULL );
if ( now.tv_sec > speed_last_update.tv_sec )
{
elapsed_time = (now.tv_sec - speed_last_update.tv_sec) + ((now.tv_usec - speed_last_update.tv_usec) / 1000000.0f);
if ( elapsed_time >= 1.0f )
{
speed = ( ( ((float) (total_len_written-old_total_len_written)) / elapsed_time) / 1024.0f );
old_total_len_written = total_len_written;
gettimeofday ( &speed_last_update, NULL );
}
}
if ( speed > 0.0f )
{
if ( (speed / 1024.0f) >= 1.0f )
fprintf ( stderr, "%s: %.2f%% (%.1f mbps) \r", output_filename, (double) total_len_written * coef, speed/1024.0f );
else
fprintf ( stderr, "%s: %.2f%% (%.1f kbps) \r", output_filename, (double) total_len_written * coef, speed );
}
else
fprintf ( stderr, "%s: %.2f%% (--.- kbps) \r", output_filename, (double) total_len_written * coef );
}
fflush ( f );
if ( delay != 0 )
{
if ( end <= time(NULL) )
{
delay = -1;
break;
}
}
}
if ( ( ret == MMS_RET_SUCCESS ) && ( !quiet ) && ( delay != -1 ) && ( !retry ) )
fprintf ( stderr, "%s: 100.00%% \r", output_filename );
}
mms_disconnect ( mms );
mms_destroy ( mms );
fclose ( f );
if ( delay == -1 )
break;
}
clean:
if ( !quiet )
fprintf ( stderr, "\n" );
if ( stddebug != NULL )
{
fprintf ( stddebug, "\n\n--> debug log ends now\n" );
fclose ( stddebug );
}
for ( block=stream_list; block!=NULL; )
{
STREAM_LIST *old;
old = block;
block = (STREAM_LIST *) block->next;
if ( old->stream != NULL )
free ( old->stream );
if ( old->output != NULL )
free ( old->output );
free ( old );
}
return (ret<0) ? (ret*-1) : ret;
}